import { Storage, STORAGE_KEYS } from './storage'
import type { ApiResponse, RequestConfig } from '../types'
import { getApiBaseURL, getCurrentConfig } from '../config'

// 请求基础配置
const config = getCurrentConfig()
const BASE_URL = getApiBaseURL()
const TIMEOUT = config.api.timeout

// 请求拦截器
const requestInterceptor = (config: RequestConfig): RequestConfig => {
  // 添加token
  const token = Storage.get<string>(STORAGE_KEYS.TOKEN)
  if (token) {
    config.headers = {
      ...config.headers,
      Authorization: `Bearer ${token}`,
    }
  }

  // 添加通用请求头
  config.headers = {
    'Content-Type': 'application/json',
    Accept: 'application/json',
    ...config.headers,
  }

  // 显示加载提示
  if (config.showLoading !== false) {
    uni.showLoading({
      title: config.loadingText || '加载中...',
      mask: true,
    })
  }

  return config
}

// 响应拦截器
const responseInterceptor = <T>(
  response: any,
  config: RequestConfig
): ApiResponse<T> => {
  // 隐藏加载提示
  if (config.showLoading !== false) {
    uni.hideLoading()
  }

  // 处理HTTP状态码
  if (response.statusCode !== 200) {
    const errorMessage = getErrorMessage(response.statusCode)
    uni.showToast({
      title: errorMessage,
      icon: 'none',
      duration: 2000,
    })
    throw new Error(errorMessage)
  }

  const result: ApiResponse<T> = response.data

  // 处理业务状态码
  if (result.code === 200 || result.success) {
    return result
  } else if (result.code === 401) {
    // token过期，清除本地存储并跳转到登录页
    handleTokenExpired()
    throw new Error('登录已过期，请重新登录')
  } else {
    // 其他业务错误
    uni.showToast({
      title: result.message || '请求失败',
      icon: 'none',
      duration: 2000,
    })
    throw new Error(result.message || '请求失败')
  }
}

// 处理token过期
const handleTokenExpired = (): void => {
  Storage.clear()
  uni.reLaunch({
    url: '/src/pages/login/login',
  })
}

// 获取错误信息
const getErrorMessage = (statusCode: number): string => {
  const errorMap: Record<number, string> = {
    400: '请求参数错误',
    401: '未授权，请重新登录',
    403: '拒绝访问',
    404: '请求地址不存在',
    405: '请求方法不允许',
    408: '请求超时',
    500: '服务器内部错误',
    501: '服务未实现',
    502: '网关错误',
    503: '服务不可用',
    504: '网关超时',
  }
  return errorMap[statusCode] || '网络错误'
}

// 核心请求方法
export const request = <T = any>(
  config: RequestConfig
): Promise<ApiResponse<T>> => {
  return new Promise((resolve, reject) => {
    // 应用请求拦截器
    const finalConfig = requestInterceptor(config)

    // 构建完整URL
    const url = finalConfig.url.startsWith('http')
      ? finalConfig.url
      : `${BASE_URL}${finalConfig.url}`

    // 构建请求参数
    const requestOptions: UniApp.RequestOptions = {
      url,
      method: finalConfig.method || 'GET',
      data: finalConfig.data,
      header: finalConfig.headers,
      timeout: finalConfig.timeout || TIMEOUT,
      success: (response: any) => {
        try {
          const result = responseInterceptor<T>(response, finalConfig)
          resolve(result)
        } catch (error: any) {
          reject(error)
        }
      },
      fail: (error: any) => {
        // 隐藏加载提示
        if (finalConfig.showLoading !== false) {
          uni.hideLoading()
        }

        uni.showToast({
          title: '网络连接失败',
          icon: 'none',
          duration: 2000,
        })
        reject(error)
      },
    }

    // 发送请求
    uni.request(requestOptions)
  })
}

// 便捷方法
export const get = <T = any>(
  url: string,
  params?: any,
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return request<T>({
    url,
    method: 'GET',
    params,
    ...config,
  })
}

export const post = <T = any>(
  url: string,
  data?: any,
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return request<T>({
    url,
    method: 'POST',
    data,
    ...config,
  })
}

export const put = <T = any>(
  url: string,
  data?: any,
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return request<T>({
    url,
    method: 'PUT',
    data,
    ...config,
  })
}

export const del = <T = any>(
  url: string,
  config?: Partial<RequestConfig>
): Promise<ApiResponse<T>> => {
  return request<T>({
    url,
    method: 'DELETE',
    ...config,
  })
}
